package com.cskaoyan.javase.array._6call;

import java.util.Arrays;

/**
 * 方法的传值/传参问题:
 *
 * 什么是方法的传值问题？
 * 调用方法时，我们需要传递实参给方法，在方法内部有可能会改变这些实参的值。
 * 那么方法执行完毕后，这些实参的值在原先的方法中会怎么变呢？这就是方法的传值问题。
 *
 * 方法的传参问题是非常重要的,因为如果不了解它,就不了解Java方法的调用
 *
 * 两个概念,两种传参的方式:
 *      1.值传递(call by value)指的是方法得到的是,实参变量的拷贝
 *          这意味着方法不能修改实参变量本身,修改的是实参变量的拷贝
 *
 *      2.引用传递(call by reference)指的是方法得到的是,实参变量的地址,也就是得到实参变量本身.
 *          这意味着方法能够修改实参变量本身
 *
 * 那么Java究竟是何种传值方式?测试一下即可:
 *      1.首先测试基本数据类型参数,我们发现方法不能修改实参变量
 *          这说明至少对于基本数据类型参数而言,Java是值传递的
 *          Java方法是不可以修改基本数据类型实参变量的取值
 *
 *      2.接下来测试引用数据类型参数,我们发现方法可以修改引用数据类型对象中元素的取值
 *      这说明至少对于引用数据类型参数而言,Java是引用传递的
 *
 *      综上,Java有值传递,基本数据类型实参
 *      有引用传递,引用数据类型实参
 *
 * 以上结论是典型的错误,是典型的互联网博主的错误
 * 是因为没有弄清楚引用数据类型和基本数据类型的区别
 *
 * 实际上,Java仅有值传递,任何时候,方法得到的都是实参变量的拷贝
 * 而不是实参变量本身,Java没有任何引用传递.
 *
 * 结论:
 *      1.Java对于基本数据类型实参而言是值传递的,这是毋庸置疑的,非常容易验证.
 *      2.Java的方法是可以修改引用数据类型实参对象中的元素的
 *          Java方法可以改变对象的状态(修改对象中元素/属性的取值)
 *      3.,我们通过一个交换数组引用的方法,验证了对于引用数据类型实参而言,Java也是值传递的
 *
 *
 * 最后再总结一下:
 *      1.Java是不可能存在引用传递的,很显然,引用传递违背了Java局部变量仅在方法内部生效的原则.
 *      2.由于局部变量仅在方法内部生效的大原则,所以:
 *          任何一个方法都不可能直接修改另外一个方法中的局部变量
 *          这包括:
 *              另外一个方法中的基本数据类型变量(局部变量)
 *              以及另外一个方法中的引用数据类型变量的引用(局部变量)
 *
 *      3.Java方法是可以修改对象的状态的
 *          方法中可以使用实参传入的引用拷贝
 *          来改变对象的状态,修改对象中元素的取值
 *          这是因为引用的拷贝和原先的引用指向的是同一个对象
 *
 * @since 10:56
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int a = 10;
        test(a);
        /*
            分析:
                1.如果a的值发生了变化,说明方法可以修改基本数据类型实参变量的取值
                    说明是引用传递
                2.如果a的值没有发生变化,说明方法不可以修改基本数据类型实参变量的取值
                    说明是值传递
         */
        System.out.println(a);
        System.out.println("---------------------");
        int[] arr = {1, 2, 3};
        System.out.println("调用方法之前:" + Arrays.toString(arr));
        test(arr);
        System.out.println("调用方法之后:" + Arrays.toString(arr));

        System.out.println("-------------------");
        int[] arr1 ={666,666,666};
        int[] arr2 = {777,777,777};
        System.out.println("交换之前arr1:"+Arrays.toString(arr1));
        System.out.println("交换之前arr2:"+Arrays.toString(arr2));
        /*
            分析:
                1.如果方法交换引用交换成功了,说明方法得到的就是传入方法的引用本身,说明Java是引用传递的
                2.如果方法交换引用交换失败了,说明方法得到的是传入方法的引用的拷贝,说明Java是值传递的
         */
        swapArrReference(arr1, arr2);
        System.out.println("交换之后arr1:" + Arrays.toString(arr1));
        System.out.println("交换之后arr2:" + Arrays.toString(arr2));
    }

    public static void test(int a) {
        a = 100;
        a = 200;
        a *= 2;
        // return 100;
    }

    public static void test(int[] arr) {
        // 在这里,将数组中的元素全部变为原先的2倍
        for (int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }
    }

    // 交换两个int数组的引用
    public static void swapArrReference(int[] arr1, int[] arr2) {
        // 交换需要temp
        int[] temp = arr1;
        arr1 = arr2;
        arr2 = temp;
        System.out.println("交换方法当中arr1:"+Arrays.toString(arr1));
        System.out.println("交换方法当中arr2:"+Arrays.toString(arr2));
    }
}
